package com.example.nettyclient.netty.handler;

import android.text.TextUtils;
import android.util.Log;

import com.example.nettyclient.netty.config.Config;
import com.example.nettyclient.netty.listener.NettyClientListener;
import com.example.nettyclient.netty.status.ConnectState;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;

//SimpleChannelInboundHandler继承自ChannelInboundHandlerAdapter
//SimpleChannelInboundHandler 里面重写、新增了 ChannelInboundHandlerAdapter 里面的方法功能 - channelRead0 和 channelRead()
//传入的泛型用于channelRead0的msg
public class NettyClientHandler extends SimpleChannelInboundHandler<String> {

    private static final String TAG = "NettyClientHandler";//用于日志的打印
    private final boolean isSendheartBeat;//是否发送心跳
    private NettyClientListener listener;//面向接口编程，这里只的是实现了NettyClientListener接口的MainActivity
    private int index;//客户端标识.(因为可能存在多个tcp连接)
    private Object heartBeatData;//心跳数据，可以是String类型，也可以是byte[]
    private String packetSeparator;//用特殊字符，作为分隔符，解决粘包问题，默认是用换行符作为分隔符

    public NettyClientHandler(NettyClientListener listener, int index, boolean isSendheartBeat, Object heartBeatData) {
        this(listener,index,isSendheartBeat,heartBeatData,null);
    }

    public NettyClientHandler(NettyClientListener listener, int index, boolean isSendheartBeat, Object heartBeatData,String separator) {
        this.listener = listener;
        this.index = index;
        this.isSendheartBeat = isSendheartBeat;
        this.heartBeatData = heartBeatData;
        this.packetSeparator = TextUtils.isEmpty(separator) ? System.getProperty("line.separator") : separator;//默认是用换行符作为分隔符
    }

    /**
     *设定IdleStateHandler心跳检测每x秒进行一次读检测，
     *如果x秒内ChannelRead()方法未被调用则触发一次userEventTrigger()方法
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if(evt instanceof IdleStateEvent){//空闲事件
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.WRITER_IDLE){//public enum IdleState 共3种状态，READER_IDLE, WRITER_IDLE,ALL_IDLE
                if(isSendheartBeat){//发送心跳
                    if(heartBeatData == null){//使用默认的心跳数据
                        ctx.channel().writeAndFlush(Config.heartBeatData + packetSeparator);
                    }else {
                        //使用自定义的心跳数据
                        if (heartBeatData instanceof String) {
                            ctx.channel().writeAndFlush(heartBeatData + packetSeparator);
                        } else if(heartBeatData instanceof byte[]) {
                            //Unpooled是Netty 提供一个专门用来操作缓冲区(即 Netty 的数据容器)的工具类。
                            ByteBuf buf = Unpooled.copiedBuffer((byte[]) heartBeatData);
                            ctx.channel().writeAndFlush(buf);
                        } else {
                            Log.e(TAG, "userEventTriggered: heartBeatData type error");
                        }
                    }
                } else {
                    Log.e(TAG, "不发送心跳");
                }
            }
        }
    }

    /**
     *客户端上线
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Log.e(TAG, "channelActive");
        listener.onClientStatusConnectChanged(ConnectState.STATUS_CONNECT_SUCCESS, index);
    }

    /**
     *客户端下线
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Log.e(TAG, "channelInactive");
    }

    /**
     * 客户端收到消息
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        Log.e(TAG, "channelRead0:"+msg);
        listener.onMessageResponseClient(msg, index);
    }

    /**
     * 异常
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        Log.e(TAG, "exceptionCaught");
        listener.onClientStatusConnectChanged(ConnectState.STATUS_CONNECT_ERROR, index);
        cause.printStackTrace();
        ctx.close();
    }
}
